/******************************************************************************
 * Spine Runtimes License Agreement
 * Last updated January 1, 2020. Replaces all prior versions.
 *
 * Copyright (c) 2013-2020, Esoteric Software LLC
 *
 * Integration of the Spine Runtimes into software or otherwise creating
 * derivative works of the Spine Runtimes is permitted under the terms and
 * conditions of Section 2 of the Spine Editor License Agreement:
 * http://esotericsoftware.com/spine-editor-license
 *
 * Otherwise, it is permitted to integrate the Spine Runtimes into software
 * or otherwise create derivative works of the Spine Runtimes (collectively,
 * "Products"), provided that each user of the Products must obtain their own
 * Spine Editor license and redistribution of the Products in any form must
 * include this license and copyright notice.
 *
 * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
 * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/

package com.esotericsoftware.spine.utils;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Pool;
import com.esotericsoftware.spine.AnimationState;
import com.esotericsoftware.spine.AnimationState.TrackEntry;
import com.esotericsoftware.spine.AnimationStateData;
import com.esotericsoftware.spine.Skeleton;
import com.esotericsoftware.spine.SkeletonData;
import com.esotericsoftware.spine.SkeletonRenderer;
import com.esotericsoftware.spine.Skin;
import com.xenoamess.cyan_potion.base.visual.Colors;
import java.util.ArrayList;

public class SkeletonActorPool extends Pool<SkeletonActor> {
    private SkeletonRenderer renderer;
    SkeletonData skeletonData;
    AnimationStateData stateData;
    private final Pool<Skeleton> skeletonPool;
    private final Pool<AnimationState> statePool;
    private final ArrayList<SkeletonActor> obtained;

    public SkeletonActorPool(SkeletonRenderer renderer, SkeletonData skeletonData, AnimationStateData stateData) {
        this(renderer, skeletonData, stateData, 16, Integer.MAX_VALUE);
    }

    public SkeletonActorPool(SkeletonRenderer renderer, SkeletonData skeletonData, AnimationStateData stateData,
                             int initialCapacity, int max) {
        super(initialCapacity, max);

        this.renderer = renderer;
        this.skeletonData = skeletonData;
        this.stateData = stateData;

        obtained = new ArrayList(false, initialCapacity);

        skeletonPool = new Pool<Skeleton>(initialCapacity, max) {
            protected Skeleton newObject() {
                return new Skeleton(SkeletonActorPool.this.skeletonData);
            }

            protected void reset(Skeleton skeleton) {
                skeleton.setColor(Colors.WHITE);
                skeleton.setScale(1, 1);
                skeleton.setSkin((Skin) null);
                skeleton.setSkin(SkeletonActorPool.this.skeletonData.getDefaultSkin());
                skeleton.setToSetupPose();
            }
        };

        statePool = new Pool<AnimationState>(initialCapacity, max) {
            protected AnimationState newObject() {
                return new AnimationState(SkeletonActorPool.this.stateData);
            }

            protected void reset(AnimationState state) {
                state.clearTracks();
                state.clearListeners();
            }
        };
    }

    /** Each obtained skeleton actor that is no longer playing an animation is removed from the stage and returned to
     *  the pool. */
    public void freeComplete() {
        ArrayList<SkeletonActor> obtained = this.obtained;
        outer:
        for (int i = obtained.size - 1; i >= 0; i--) {
            SkeletonActor actor = obtained.get(i);
            ArrayList<TrackEntry> tracks = actor.state.getTracks();
            for (int ii = 0, nn = tracks.size; ii < nn; ii++)
                if (tracks.get(ii) != null)
                    continue outer;
            free(actor);
        }
    }

    protected SkeletonActor newObject() {
        SkeletonActor actor = new SkeletonActor();
        actor.setRenderer(renderer);
        return actor;
    }

    /** This pool keeps a reference to the obtained instance, so it should be returned to the pool via
     *  {@link #free(SkeletonActor)}
     * , {@link #freeAll(ArrayList)} or {@link #freeComplete()} to avoid leaking memory. */
    public SkeletonActor obtain() {
        SkeletonActor actor = super.obtain();
        actor.setSkeleton(skeletonPool.obtain());
        actor.setAnimationState(statePool.obtain());
        obtained.add(actor);
        return actor;
    }

    protected void reset(SkeletonActor actor) {
        actor.remove();
        obtained.removeValue(actor, true);
        skeletonPool.free(actor.getSkeleton());
        statePool.free(actor.getAnimationState());
    }

    public ArrayList<SkeletonActor> getObtained() {
        return obtained;
    }
}
